﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Windows.Forms;
using Cjwdev.WindowsApi;
using Microsoft.Win32;
using static LocalWindowsService.SysLog;
namespace LocalWindowsService
{
    public partial class LRomateSever : ServiceBase
    {

        public LRomateSever()
        {
            //
            InitializeComponent();

        }
        protected override void OnStart(string[] args)
        {
            try
            {

                this.Timer_KeepAlive.Elapsed += Timer_KeepAlive_Tick;

                Timer_KeepAlive.Enabled = true;

                RegistryDesktopMirror();
            }
            catch (Exception ex)
            {
                WriteEntry(ex);
            }
        }
        protected override void OnStop()
        {
            try
            {
                Timer_KeepAlive.Enabled = false;
                this.Timer_KeepAlive.Elapsed -= Timer_KeepAlive_Tick;

                KillProcessExists(StrServer);
                WriteEntry("关闭服务");
                UnRegistry();
            }
            catch (Exception ex)
            {

                WriteEntry(ex);
            }
        }
        private void Timer_KeepAlive_Tick(object sender, EventArgs e)
        {
            try
            {
                // 判断Server.exe是否存在，如果不存在启动一个，如果存在则不做什么
                if (!ServerExist(StrServer))
                {
                    StartLocalServer();
                }
            }
            catch (Exception ex)
            {
                WriteEntry(ex);
            }

        }
        private bool ServerExist(string serverExe)
        {
            return System.Diagnostics.Process.GetProcesses().Any(p => p.ProcessName == serverExe);
        }

        private void KillProcessExists(string serverExe)
        {
            Process[] processes = Process.GetProcessesByName(serverExe);
            foreach (Process p in processes.Where(p => p.ProcessName == serverExe))
            {
                //p.CloseMainWindow();
                //这货的窗口被我隐藏了，没法通过窗口消息的方式通知到，只能用暴力的方式了。
                p.Kill();
                p.Close();
                WriteEntry($"关闭服务时，成功杀死进程:{serverExe}");
            }
        }

        #region Registry

        private const string driverDeviceNumber = "DEVICE0";
        private const string driverMiniportName = "dfmirage";
        private const string driverName = "Mirage Driver";
        private const string driverRegistryPath = "SYSTEM\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Services";
        private RegistryKey _registryKey;
        private void RegistryDesktopMirror()
        {
            WriteEntry("_registryKey Start");
            _registryKey = Registry.LocalMachine.OpenSubKey(driverRegistryPath, true);
            if (_registryKey != null)
                _registryKey = _registryKey.CreateSubKey(driverMiniportName);
            else
                WriteEntry("Couldn't open registry key");

            if (_registryKey != null)
                _registryKey = _registryKey.CreateSubKey(driverDeviceNumber);
            else
                WriteEntry("Couldn't open registry key");

            //			_registryKey.SetValue("Cap.DfbBackingMode", 0);
            if (_registryKey != null)
            {
                _registryKey.SetValue("Screen.ForcedBpp", 24);
                _registryKey.SetValue("Attach.ToDesktop", 1);
            }
            WriteEntry("_registryKey End");
        }
        private void UnRegistry()
        {
            if (_registryKey != null)
            {
                _registryKey.SetValue("Attach.ToDesktop", 0);
                _registryKey.Close();
            }
        }

        #endregion

        #region StartApp
        private void StartLocalServer()
        {
            string appPath = AppDomain.CurrentDomain.BaseDirectory +
                             $"{StrServer}.exe";
            WriteEntry($"尝试启动本地服务{StrServer}.exe,路径为:{appPath}");
            StartApp(appPath);
        }


        private const string StrServer = "Server";
        private int _currentAquariusProcessId;

        // ReSharper disable once InconsistentNaming
        private const int STARTF_USESHOWWINDOW = 0x00000001;
        // ReSharper disable once InconsistentNaming
        private const int SW_HIDE = 0;

        private void StartApp(string strAppPath)
        {
            try
            {
                IntPtr userTokenHandle = IntPtr.Zero;
                ApiDefinitions.WTSQueryUserToken(ApiDefinitions.WTSGetActiveConsoleSessionId(), ref userTokenHandle);

                ApiDefinitions.PROCESS_INFORMATION procInfo;
                ApiDefinitions.STARTUPINFO startInfo = new ApiDefinitions.STARTUPINFO();
                startInfo.cb = (uint)Marshal.SizeOf(startInfo);

                startInfo.dwFlags = STARTF_USESHOWWINDOW;
                startInfo.wShowWindow = SW_HIDE;
                ApiDefinitions.CreateProcessAsUser(
                    userTokenHandle,
                    strAppPath,
                    "",
                    IntPtr.Zero,
                    IntPtr.Zero,
                    false,
                    0,
                    IntPtr.Zero,
                    null,
                    ref startInfo,
                    out procInfo);

                if (userTokenHandle != IntPtr.Zero)
                    ApiDefinitions.CloseHandle(userTokenHandle);

                _currentAquariusProcessId = (int)procInfo.dwProcessId;
            }
            catch (Exception ex)
            {
                WriteEntry(ex);
            }
        }

        #endregion


        private void WriteLog(string log)
        {
            using (var sw = new System.IO.StreamWriter($"C:\\log.txt", true))
            {
                sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + log);
            }
        }
    }
}
